/**
 * @file ThreadPool.cc
 * @author zziywang (zziywang@163.com)
 * @brief { life is too short to learn cpp! }
 * @version 1.0
 * @date 2022-05-08
 *
 * @copyright Copyright (c) 2022
 *
 */

#include "ThreadPool.hh"
#include <iostream>
#include <unistd.h>
using std::cout;
using std::endl;
#define DEBUG

namespace snow
{

ThreadPool::ThreadPool(size_t threadNum, size_t queSize)
    : threadNum_(threadNum),
      queSize_(queSize),
      taskQue_(queSize),
      isExit_(false)
{
    threads_.reserve(threadNum_);
}

ThreadPool::~ThreadPool()
{
    if (isExit_) {
        stop();
    }
}

// 线程池启动
void ThreadPool::start()
{
    // 批量创建线程对象
    for (int i = 0; i < threadNum_; ++i) {
        unique_ptr<Thread> thread(new Thread(
            std::bind(&ThreadPool::CallBack, this),
            "线程池第" + std::to_string(i + 1) + "号子线程"));
        threads_.push_back(std::move(thread));
    }
    // 激活线程
    for (auto &thread : threads_) {
        thread->start();
    }
}

void ThreadPool::CallBack()
{
    while (!isExit_) {
#ifdef DEBUG
        static int taskNum = 1;
#endif
        Task task = getTask(); // 取任务执行
        if (task) {
#ifdef DEBUG
            cout << "线程" << tls::threadName
                 << "取走了第" << taskNum++ << "个任务" << endl;
#endif
            task(); // 执行回调
        }
    }
}

// 线程池退出机制
void ThreadPool::stop()
{
    if (!isExit_) {
        // 把当前任务执行完
        while (!taskQue_.empty()) {
            usleep(1);
        }
        // 当任务执行速度过快，在_isExit设置为True之前，
        // 每个子线程都已经取任务，此时发现taskQue为空
        // 所有子线程都会阻塞在notEmpty的条件变量之上，从而无法退出
        isExit_ = true;
        taskQue_.notifyExit();
        for (auto &thread : threads_) {
            thread->join();
        }
    }
}

// 生产者消费者
void ThreadPool::addTask(const Task &task)
{
    taskQue_.push(std::move(task));
}

Task ThreadPool::getTask()
{
    return taskQue_.pop();
}

} // namespace snow